Helper.using('py.Math', function (ns) {

    // ax^2 + by^2 + cxy + dx + cy + f = 0
    ns.Equation = function (a, b, c, d, e, f) {
        this.setType('Equation');
        this.a = a;
        this.b = b;
        this.c = c;
        this.d = d;
        this.e = e;
        this.f = f;
    };


    // ax + by = c
    ns.LineEquation = function (a, b, c) {
        ns.Equation.apply(this, [0, 0, 0, a, b, -c]);
        this.setType('LineEquation');

        // ax + by = c
        // x = (c - by)/a
        // y = (c - ax)/b

        this.getX = function (y) {
            return (c - b * y) / a;
        };

        this.getY = function (x) {
            return (c - a * x) / b;
        };

        this.toString = function () {
            return [a, "x + ", b, "y = ", c].join('');
        }


        // intersection
        this.inbound = function (x1, x2, y1, y2) {
            var x = this.getX, y = this.getY,
                a = y(x1),
                b = x(y1),
                c = y(x2),
                d = x(y2),
                ret = [];

            a >= y1 && a <= y2 && ret.push({x:x1, y:a});
            c >= y1 && c <= y2 && ret.push({x:x2, y:c});
            b >= x1 && b <= x2 && ret.push({x:b, y:y1});
            d >= x1 && d <= x2 && ret.push({x:d, y:y2});
            return ret;
        }
    }

    ns.CircleUtils = {
        // tâm đường tròn ngoại tiếp tam giác
        getCircleCenterFromPoints:function (array) {
            var a = array[0], b = array[1], c = array[2], center = {x:NaN, y:NaN};

            center.x = (.5 *
                ((a.x * a.x + a.y * a.y) * (c.y - b.y) +
                    (b.x * b.x + b.y * b.y) * (a.y - c.y) +
                    (c.x * c.x + c.y * c.y) * (b.y - a.y)
                    ) /
                (
                    a.y * (b.x - c.x) +
                        b.y * (c.x - a.x) +
                        c.y * (a.x - b.x)
                    ));

            center.y = (.5 *
                ((a.x * a.x + a.y * a.y) * (b.x - c.x) +
                    (b.x * b.x + b.y * b.y) * (c.x - a.x) +
                    (c.x * c.x + c.y * c.y) * (a.x - b.x)
                    ) /
                (
                    a.y * (b.x - c.x) +
                        b.y * (c.x - a.x) +
                        c.y * (a.x - b.x)
                    ))
            ;
            return center;
        }
    };

    ns.distance = function (p1, p2) {
        return {x:p2.x - p1.x, y:p2.y - p1.y};
    }

    ns.addVector = function (a, b) {
        return {x:a.x + b.x, y:a.y + b.y};
    }

    ns.getVerteciesOfRegularPolygon = function (point1, point2, vertexCount) {
        var p1 = {};
        var p2 = {};
        p1.x = point1.getX();
        p1.y = point1.getY();
        p2.x = point2.getX();
        p2.y = point2.getY();
        var mx = (p1.x + p2.x) / 2; //midPoint.x
        var my = (p1.y + p2.y) / 2; //midPoint.y
        var p1_p2 = Math.sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
        var p1_m = Math.sqrt((mx - p1.x) * (mx - p1.x) + (my - p1.y) * (my - p1.y));
        var anglePolygon = Math.PI / vertexCount;
        var apothem = p1_m / Math.tan(anglePolygon);
        var cosOMOx = (p2.y - p1.y) / p1_p2;
        var cosOMOy = (p1.x - p2.x) / p1_p2;
        var circleCenter = {};
        circleCenter.x = mx + apothem * cosOMOx;
        circleCenter.y = my + apothem * cosOMOy;

        var rx, ry;
        rx = p2.x - circleCenter.x;
        ry = p2.y - circleCenter.y;

        var count;
        var _rx, _ry;
        var returnPoints = [];
        returnPoints[0] = p1;
        returnPoints[1] = p2;

        for (count = 2; count < vertexCount; ++count) {
            _rx = rx * Math.cos(-2 * anglePolygon) - ry * Math.sin(-2 * anglePolygon);
            _ry = rx * Math.sin(-2 * anglePolygon) + ry * Math.cos(-2 * anglePolygon);
            rx = _rx;
            ry = _ry;
            returnPoints[count] = {x:(circleCenter.x + rx), y:(circleCenter.y + ry)};
        }
        return returnPoints;
    }
});
